package com.fingard.dsp.bank.directbank.cib02.utils;

import com.fingard.dsp.bank.directbank.jhbank01.utils.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;

/**
 * @author Parker on 2019-11-29.
 * @version 1.0
 */
public class RSA {
    /**
     * 指定key的大小
     */
    private static int KEYSIZE = 2048;
    public static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";

    /**
     * 加密方法 source： 源数据
     */
    public static String encrypt(String source, String publicKey, String charset) throws Exception {
        ObjectInputStream inputStream = null;
        try {
            inputStream = new ObjectInputStream(new FileInputStream(publicKey));
            Key key = (PublicKey) inputStream.readObject();
            /** 得到Cipher对象来实现对源数据的RSA加密 */
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] b = source.getBytes(charset);
            int bLength = b.length;
            // 最大加密字节数，超出最大字节数需要分组加密
            int MAX_ENCRYPT_BLOCK = 117;
            // 标识
            int offSet = 0;
            byte[] resultBytes = {};
            byte[] cache = {};

            /** 执行分段加密操作 */
            while (bLength - offSet > 0) {
                if (bLength - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(b, offSet, MAX_ENCRYPT_BLOCK);
                    offSet += MAX_ENCRYPT_BLOCK;
                } else {
                    cache = cipher.doFinal(b, offSet, bLength - offSet);
                    offSet = bLength;
                }
                resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
                System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
            }
            return new String(Base64.encodeBase64(resultBytes), charset);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    /**
     * 解密算法 cryptograph:密文
     */
    public static String decrypt(String cryptograph, String privateKey, String charset) throws Exception {
        ObjectInputStream inputStream = null;
        ByteArrayOutputStream out = null;
        try {
            inputStream = new ObjectInputStream(new FileInputStream(privateKey));
            Key key = (PrivateKey) inputStream.readObject();
            /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] b1 = Base64.decodeBase64(cryptograph.getBytes(charset));
            int MAX_DECRYPT_BLOCK = 128;
            int b1Length = b1.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            byte[] decryptedData = null;
            // 对数据分段解密
            while (b1Length - offSet > 0) {
                if (b1Length - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(b1, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(b1, offSet, b1Length - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            decryptedData = out.toByteArray();
            return new String(decryptedData, charset);
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        } finally {
            if (out != null) {
                out.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

}
